#ifndef HERM_SOCKET_STREAM_H
#define HERM_SOCKET_STREAM_H

#include "herm/export_symbols.h"
#include "herm/base/socket/socket_base.h"

namespace herm{

/**
 * @brief Connector that connects to server and generates a Stream.
 *
 * @author Huang RuiGuang
 * @date 2008/12/1
 *
 * Herm library
 * Copyright (c) 2008 by Huang RuiGuang(daemon.huang@gmail.com)
 *
 * Permission to use, copy, modify, distribute and sell this software.
 */
class Stream;
class Address;
class HERM_API Connector
{
public:
	Connector(void);
	~Connector(void);

	/**
     * @brief Connect blocking to server and attach a handle to \a s. \n
	 *        Connect successfully, allocate a pair of random ip&port.
	 */
	void Connect(const Address& remoteAddr, Stream& s, bool isReuseAddr = false);

	/**
     * @brief Connect blocking to server and attach a handle to \a s. \n
	 *        Connect successfully, bind to \a localAddr.
	 */
	void Connect(const Address& localAddr, const Address& remoteAddr, Stream& s, bool isReuseAddr = false);

	/**
     * @brief Connect nonblocking to server and attach a handle to \a s.
	 * @note \a s will be a nonblocking stream.
	 * @exception Occur error, throw herm::Exception.
	 */
	void ConnectNB(const Address& remoteAddr, Stream& s, bool isReuseAddr = false);
	void ConnectNB(const Address& localAddr, const Address& remoteAddr, Stream& s, bool isReuseAddr = false);
private:
	void DoConnect(const Address& remoteAddr, Stream& s);
	void DoConnectNB(const Address& remoteAddr, Stream& s);
};

/**
 * @brief  Acceptor that listens, accept connection from client and create\n
 *         a socket handle to communication with client.
 *
 * @author Huang RuiGuang
 * @date 2008/12/1
 *
 * Herm library
 * Copyright (c) 2008 by Huang RuiGuang(daemon.huang@gmail.com)
 *
 * Permission to use, copy, modify, distribute and sell this software.
 */
class HERM_API Acceptor : public BasicSocket<Private::StreamType>
{
public:
	/**
     * @brief Create a server socket.
	 * @param [addr] Attach addr for binding.
	 * @exception Occurred error, throw herm::Exception.
	 * @remarks Create a socket handle, attach to \a addr and begin to\n
	 *         listen from client connection.
	 * @see Address
	 */
	Acceptor(const Address& addr, bool isReuseAddr = false);
	~Acceptor(void);

	/**
     * @brief Accept blocking a connection from client, and create connection handle\n
	 *        to attach to \a s.
	 * @param [s] Stream to be attached by created socket handle.
	 * @exception Occurred error, throw herm::Exception.
	 */
	void Accept(Stream& s);

	/**
     * @brief In addition to get the address of client socket.
	 */
	void Accept(Stream& s, Address& addr);

	/**
	 * @brief Accept nonblocking a connection.
	 * @return herm::COMPLETION, no connections are present to be accepted.\n
	 *         herm::PENDING, some connections can be accepted.
	 * @note Accepted stream will be a nonblocking socket!
	 */
	int AcceptNB(Stream& s);
	int AcceptNB(Stream& s, Address& addr);
};

/**
 * @brief TCP stream's receiving and sending.
 * @note Blocking io must use ReceiveN & SendN; nonblocking io must\n
 *       use Receive&Send.
 *
 * @author Huang RuiGuang
 * @date 2008/12/1
 *
 * Herm library
 * Copyright (c) 2008 by Huang RuiGuang(daemon.huang@gmail.com)
 *
 * Permission to use, copy, modify, distribute and sell this software.
 */
class HERM_API Stream : public BasicSocket<Private::StreamType>
{
public:
	Stream(void);
	~Stream(void);

	/**
 	 * @brief Use 'block' io, send \a length count bytes.\n
	 *        if succefully, the sent bytes must is \a length.
	 * @exception Error occured, throw herm::Exception exception.
	 */
	void Send(const char* buffer, int length);
	
	/**
	 * @brief Use 'block' io, receive \a length bytes.
	 * @return  Return value > 0, is received bytes;\n 
	 *          == 0, the remote peer is close.
	 * @exception Occur error, throw herm::Exception exception.
	 */
	int Receive(char* buffer, int length);

	/**
	 * @brief 'Nonblock' io, try to send \a length bytes.
	 * @return >0, is sent bytes;\n 
	 *         herm::COMPLETION TCP stack buffer is full.
	 * @exception Occur error, throw herm::Exception. 
	 */
	int SendNB(const char* buffer, int length);
	/**
	* @brief 'Nonblock' io, try to receive \a length bytes.
	* @return, > 0, is received bytes;
	*          0, the remove peer is close;
	*          herm::COMPLETION, TCP receive buffer is empty, receiving returns immediately. 
	*  occur error, throw herm::Exception.
	*/
	int ReceiveNB(char* buffer, int length);
};
}

#endif

